
#include "./scheduler.hpp"
#include <spdlog/spdlog.h>
#include <ctime>

namespace qbe::ecs {

void Scheduler::runStage(World& world) {
  // std::vector<std::reference_wrapper<system>> curr_sys;
  // std::copy_if(_systems.begin(), _systems.end(), std::back_inserter(curr_sys), [this](const system& sys) { return std::get<1>(sys) == *_stage; });

  // /* this part could be multi-threaded */
  // for (auto sys : curr_sys) {
  //   // SPDLOG_INFO("system: {}", std::get<1>(sys.get()).name());
  //   auto time_start = std::clock();
  //   auto f = std::get<0>(sys.get());
  //   f(world);
  //   auto time_end = std::clock();
  //   auto name = typeid(f).name();
  //   auto time_err = std::clock() - time_start;
  //   SPDLOG_INFO("system: {}, time: {:.2f}", typeid(f).name(), time_end - time_start);

  //   // std::get<0>(sys.get())(world);
  // }

  for (auto& sys : _systems_map[*_stage]) {
    auto time_start = std::clock();
    sys(world);
    auto time_end = std::clock();
    _systems_times[*_stage] += static_cast<double>(time_end - time_start);
    // if (_fps_time >= 1000.0) {
    //   SPDLOG_INFO("stage: {}, time: {:.2f}", _stage->name(), static_cast<double>(time_end - time_start));
    // }
  }

  _stage++;
}

void Scheduler::runStartStages(World& world) {
  _stage = _at_start_schedule.begin();
  SPDLOG_INFO("run system -------------start----------");
  while (_stage != _at_start_schedule.end()) {
    runStage(world);
  }
  SPDLOG_INFO("run system -------------end ----------");
}

void Scheduler::runStages(World& world) {

  _stage = _schedule.begin();
  while (_stage != _schedule.end()) {
    runStage(world);
  }

  bool print_fps = false;
  if (!print_fps) {
    return;
  }

  _fps_cnt += 1;
  auto _fps_time = static_cast<double>(std::clock() - _fps_pre_time);
  if (_fps_time >= 1000.0) {
    SPDLOG_INFO(" \n ");
    SPDLOG_INFO(" Frame -------------start----------");
    _fps_pre_time = std::clock();

    SPDLOG_INFO("fps: {}", _fps_cnt);
    _fps_cnt = 0;

    double total_time = 0;
    for (auto& s : _schedule) {
      auto t = _systems_times[s];
      total_time += t;
      if (t >= 1)
        SPDLOG_INFO("stage: {}, time: {:.2f}", s.name(), t);
      _systems_times[s] = 0;
    }

    SPDLOG_INFO("total time: {:.2f}", total_time);
    SPDLOG_INFO("Frame -------------end----------");
    SPDLOG_INFO(" \n ");
  }
}

void Scheduler::go() {
  runStages(*_world);
}

void Scheduler::run_setup(World& world) {
  runStartStages(world);
}

void Scheduler::run(World& world) {
  // runStartStages(world);

  runStages(world);

  // _world = &world;
  // connect(&timer, &QTimer::timeout, this, &Scheduler::go);
  // timer.start(10);

  // 线程池
  // runStartStages(world);
  // _world = &world;
  // QThreadPool* threadPool = QThreadPool::globalInstance();
  // auto runnable = new SchedulerRunTask(this, world);
  // threadPool->start(runnable);  // 提交任务到线程池

  // 创建一个新的线程并将其赋值给 unique_ptr
  // runStartStages(world);
  // _run_thread = std::make_shared<std::thread>([&] {
  //   while (!_stop) {
  //     if (_cnt > 30) {
  //       _cnt = 31;
  //       // 加锁
  //       std::lock_guard<std::mutex> lock(_mutex);
  //       // SPDLOG_INFO("run");
  //       runStages(*_world);
  //       _world->clear_events();
  //     }
  //     _cnt += 1;
  //     std::this_thread::sleep_for(std::chrono::milliseconds(16));  // 延时2秒
  //   }
  //   auto close = _world->get_resource<Event<AppExit>>();
  //   if (close && close.value().get().event_queue.size() > 0) {
  //     _stop = true;
  //   }
  // });
  // _run_thread->detach();
}

}  // namespace qbe::ecs